package com.bid.base.common.util.auth;

import com.alibaba.fastjson.JSONObject;
import com.bid.base.common.entity.CommonEnums;
import com.bid.base.common.entity.OctoSub;
import com.bid.base.common.response.ApiResult;
import com.bid.base.common.response.ErrorCode;
import com.bid.base.common.util.CommonHttp;
import com.bid.base.common.util.Stringer;
import com.bid.base.common.util.auth.loginEnum.EnumLoginTran;
import com.bid.base.common.util.sm4.Sm4Util;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.slf4j.MDC;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * <strong>Description : </strong> <br>
 * <p>
 * <strong>北京正源德标科技信息有限责任公司</strong> <br>
 * </p>
 * <br>
 *
 * @author : zhaots
 * @date Date : 2021年04月12日 10:51
 * 修改人 修改日期 修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 */
@Slf4j
public class LoginConAssistant {


    public static ApiResult  logoutWrapper(String subSys, String scope, RedissonClient redissonClient){
        //登出的逻辑  1.  自己  2.通知（认证中心）所有
        log.info("登出的逻辑执行octoId:{},subSys:{},scope",subSys,scope);

        Map<String, String> map = MDC.getCopyOfContextMap();
        String userId = map.get(CommonEnums.MdcKey.USEID.getName());
        String userName = map.get(CommonEnums.MdcKey.USER_NAME.getName());

        Assert.assertNotNull("userId非空",userId);
        String keyInRedis = AuthAssistant.getTokenKeyInRedis(userId, scope,AuthAssistant.octoRedisPreffix);
        RBucket<Object> bucket = redissonClient.getBucket(keyInRedis);
        Object o = bucket.get();
        if(Stringer.isNullOrEmpty(o)){
            log.error("缓存异常，没有找到");
            return ApiResult.paramError("请求异常");
        }
        //清除本机登出逻辑
        bucket.delete();
        log.info("清除本机登出逻辑成功，清除key：{}",keyInRedis);

        return ApiResult.success("清除本机");
//        Map<String,String> params = new HashMap<String,String>();
//        params.put("octoid",octoid);
//        params.put("secret",octosecret);
//        params.put("userId",userId);
//        params.put("scope",scope);
//        params.put("userName",userName);
//        params.put("subSys",subSys);
//
//        String s = super.postInSubSys(octoUrlLogout, params);
//        log.info("子系统之间tokenUrl：{},子系统的返回是：{}", octoUrlLogout,s);
    }


    protected static String decrypt(String body,String sm4Httpkey) throws Exception {
        log.info("解密前：\t " + body);
        String deStr = Sm4Util.decryptEcb(sm4Httpkey, body);
        log.info("解密后：\t " + deStr);
        return deStr;
    }

    public static ApiResult callbackLogout(HttpServletRequest request,String body,String sm4Httpkey,RedissonClient redissonClient){
        try {
            log.info("接收到回调的登出请求");
            body = decrypt(body,sm4Httpkey);
            JSONObject jsonObject = JSONObject.parseObject(body);
            // 伪代码之模拟secret在子系统之间的加密传输 获取ac
            log.info("解密之后的数据是1： \t {}",body);
//            Object octoid = jsonObject.get("octoid");
            Object userId = jsonObject.get("userId");
            Object scope = jsonObject.get("scope");
            AuthAssistant.clearLocalOctoToken(redissonClient,userId.toString(),scope.toString(),AuthAssistant.octoRedisPreffix);
            String tokenKey = AuthAssistant.getTokenKeyInRedis(userId.toString(),scope.toString(),AuthAssistant.octoRedisPreffix);
            redissonClient.getBucket(tokenKey).delete();
            log.info("清除本地的缓存成功");
        } catch (Exception e) {
            log.error("解密异常{}",e);
            return ApiResult.paramError(e.getMessage());
        }
        return ApiResult.success("成功");
    }


    public static ApiResult noLoginWrapper(HttpServletRequest request){
        log.info("action get nologin " + request.getRequestURI());
        Enumeration<String> headerNames = request.getHeaderNames();
        StringBuilder headerinfo = new StringBuilder();
        headerinfo.append("\r\n");
        while (headerNames.hasMoreElements()){
            String s = headerNames.nextElement();
            String header = request.getHeader(s);
            headerinfo.append(s + " : " + header + "\r\n");
        }
        log.info("find nologin req，action !!!\t" + headerinfo);
        Object attribute = request.getAttribute(CommonEnums.MdcKey.AUTH_CODE.getName());
        //支持自定义
        if(!Stringer.isNullOrEmpty(attribute)){
            Integer integer = Integer.valueOf(attribute.toString());
            return ApiResult.error(ErrorCode.of(integer));
        }
        return ApiResult.noLogin();
    }

    public static ApiResult callbackUrlWrapper(String code, String state, String scope, String loginRandomStr, String userName, String subSys, String subjectType, String loginType
            , String octoid, String octosecret, String tokenUrl, RedissonClient redissonClient, String sm4Httpkey, String loginTid, String capacityType, String sdeptCode, String sdeptName) {
        return callbackUrlWrapper(code, state, scope, loginRandomStr, userName, subSys, subjectType, loginType, octoid, octosecret, tokenUrl, redissonClient, sm4Httpkey, loginTid, capacityType, sdeptCode, sdeptName);


    }
        /**
         * 青典智库咨询有限责任公司
         * @params  []
         * @return   com.bid.base.common.response.ApiResult
         * @创建时间 2022/3/31
         * @创建人 zhaots
         * @描述
         */
    public static ApiResult callbackUrlWrapper(String code
            ,String state,String scope,String loginRandomStr,String userName,String subSys,String subjectType,String loginType
            ,String octoid,String octosecret,String tokenUrl,RedissonClient redissonClient,String sm4Httpkey,String loginTid,String capacityType,String sdeptCode,String sdeptName,String userId) {

        if (Stringer.isNullOrEmpty(state, subjectType, code, subSys, scope, loginRandomStr)) {
            log.info("参数异常请检查 state,subjectType,code,subSys,scope,loginRandomStr ");
            return ApiResult.paramError();
        }
        if (Stringer.isNullOrEmpty(loginType)) {
            loginType = com.bid.base.common.entity.CommonEnums.LoginType.USERPWD.getCode();
        }

        log.info("octo receive the callback of octo,code:{},state:{},loginType:{}", code, state, scope, loginType);
        //组装参数map
        Map<String, String> params =assemParamMap(code, scope, loginRandomStr, userName, subSys, subjectType, loginType, octoid, octosecret, loginTid, capacityType, sdeptCode, sdeptName);
        log.info("octo receive the callback , tokenUrl is：{},paramMap is：{}", tokenUrl, JSONObject.toJSON(params));
        //获取token
        String s = CommonHttp.postEncrypt(tokenUrl, params, sm4Httpkey, null);
        //获取token的结果
        log.info("子系统之间的调用返回：{}", s);
        if (com.bid.base.common.util.Stringer.isNullOrEmpty(s)) {
            return ApiResult.error("数据异常（子系统之间）");
        }
        ApiResult apiResult = JSONObject.parseObject(s, ApiResult.class);
        if (!CommonHttp.requestSucc(apiResult)) {
            return ApiResult.error("数据异常（子系统之间）");
        }
        Object data = apiResult.getData();
        OctoSub octoSub = JSONObject.parseObject(data.toString(), OctoSub.class);

        //那自己的code  secret获取 ac
        //https://zhidao.baidu.com/question/987022405846948339.html
        //https://blog.csdn.net/xiejin2008/article/details/84612656?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control
        //https://processon.com/diagraming/5fe29a04e401fd39f866297d
        //TODO...按理说 接入端（相对于认证中心），应该知道我是那个端登录了。。。
        AuthAssistant.saveOctoToke2redis(redissonClient, loginRandomStr, octoSub, scope, AuthAssistant.octoRedisPreffix);
        //暂时给前端用
        com.bid.base.common.entity.OctoSub octoSubView = new com.bid.base.common.entity.OctoSub();
        octoSubView.setAccessToken(octoSub.getAccessToken());
        octoSubView.setRedirectView(octoSub.getRedirectView());
        octoSubView.setSubjectType(subjectType);
        octoSubView.setLoginType(octoSub.getLoginType());
        octoSubView.setUserId(userId);
        return ApiResult.success(octoSubView);
    }

    private static Map<String, String> assemParamMap(String code, String scope, String loginRandomStr, String userName, String subSys, String subjectType, String loginType, String octoid, String octosecret, String loginTid, String capacityType, String sdeptCode, String sdeptName) {

        Map<String, String> params = new HashMap<String, String>(16);

        params.put(EnumLoginTran.OCTO_ID.getName(), octoid);
        params.put(EnumLoginTran.OCTO_SECRET.getName(), octosecret);
        params.put(EnumLoginTran.CODE.getName(), code);
        params.put(EnumLoginTran.GRANT_TYPE.getName(), scope);
        params.put(EnumLoginTran.LOGIN_RANDOM.getName(), loginRandomStr);
        params.put(EnumLoginTran.UNAME.getName(), userName);
        params.put(EnumLoginTran.SUBSYS.getName(), subSys);
        params.put(EnumLoginTran.SUBJECT_TYPE.getName(), subjectType);
        params.put(EnumLoginTran.LOGIN_TYPE.getName(), loginType);
        params.put(EnumLoginTran.LOGIN_TID.getName(), loginTid);
        //capacityType 2021-10-11
        params.put(EnumLoginTran.CAPA_TYPE.getName(), capacityType);
        params.put(EnumLoginTran.SUR_DEPT_CODE.getName(), sdeptCode);
        params.put(EnumLoginTran.SUR_DEPT_NAME.getName(), sdeptName);

        return params;
    }
}
